######################################################################
# File: commands/__init__.py                       Part of DjangoMUD #
#                                                                    #
# Copyright (C) 2010, Joachim Pileborg and individual contributors.  #
# All rights reserved.                                               #
#                                                                    #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met:                                                           #
#                                                                    #
#   o Redistributions of source code must retain the above copyright #
#     notice, this list of conditions and the following disclaimer.  #
#   o Redistributions in binary form must reproduce the above        #
#     copyright notice, this list of conditions and the following    #
#     disclaimer in the documentation and/or other materials         #
#     provided with the distribution.                                #
#   o Neither the name of DjangoMUD nor the names of its             #
#     contributors may be used to endorse or promote products        #
#     derived from this software without specific prior written      #
#     permission.                                                    #
#                                                                    #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             #
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        #
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           #
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           #
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS  #
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,#
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,           #
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR #
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       #
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     #
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF #
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF    #
# SUCH DAMAGE.                                                       #
######################################################################

from djangomud import log

######################################################################

class BaseCommand(object):
    """
    This is the base of all commands in the MUD.
    """

    # The actual command verb, has to be set by all commands
    # This can also be a tupple or a list, if a single command can
    # have multiple command verbs.
    command = None

    def execute(self, args=None, caller=None, verb=''):
        """
        This function is called on all commands to execute them.

        args is a list of arguments to the command.
        caller is the character invoking the command.

        Note that the caller can be both a player and a monster.
        The caller can also be None.
        """
        # TODO: Add to the docstring when the caller can be None
        pass

######################################################################

# Register all commands

_all_commands = ()

def _register_command(command_class):
    global _all_commands
    _all_commands += ((command_class.command, command_class),)

def _register_commands_in_module(module):
    command_classes = [v for k,v in module.__dict__.items()
                       if type(v) == type(BaseCommand) and v.__name__ != 'BaseCommand']
    for command_class in command_classes:
        _register_command(command_class)

def _get_modules():
    import os
    directory, filename = os.path.split(__file__)
    files = [f for f in os.listdir(directory)
             if os.path.splitext(f)[1] == '.py' and os.path.splitext(f)[0] != '__init__']
    return [os.path.splitext(f)[0] for f in files]

if not _all_commands:
    from django.utils import importlib
    log.info('Registering commands')
    module_names = _get_modules()
    for module_name in module_names:
        module = importlib.import_module('.' + module_name, __name__)
        _register_commands_in_module(module)

######################################################################

def _split_args(line):
    """Function to split command line arguments into an array."""
    import re
    match_stringre = re.compile(r"""
    \""" ([^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*)
    (?: \""" )?
|   " ([^"\\\n]* (?: \\. [^"\\\n]* )*) "?
|   ''' ([^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*)
    (?: ''' )?
|   ' ([^'\\\n]* (?: \\. [^'\\\n]* )*) '?
""", re.VERBOSE | re.DOTALL)

    args = match_stringre.split(line)
    args = [a for a in args if a is not None]
    return [a for a in args if a]

def _find_command(verb):
    for command in _all_commands:
        if verb in command[0]:
            return command[1]
    return None

def execute_command(line, caller=None):
    """
    This is the command parser of the MUD server.
    """
    # First check for a special case: If the first word is followed by
    # a comma, it is the name of a character, and we interpret it as a
    # 'tell' to that character.
    if line.partition(',')[1]:
        # It might be a tell, find a logged in user with the name
        # specified
        name, sep, message = line.partition(',')
        log.warning('Short tells are not implemented yet')
        return

    # Split the line into two parts: command verb, and the rest
    verb, sep, rest = line.partition(' ')

    # Split the rest into arguments
    args = _split_args(rest)

    # Now find the command, and execute it
    command = _find_command(verb)

    if command is not None:
        command().execute(args=args, caller=caller, verb=verb)

######################################################################
